# uncompyle6 version 3.2.3
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.6.8 |Anaconda custom (64-bit)| (default, Feb 21 2019, 18:30:04) [MSC v.1916 64 bit (AMD64)]
# Embedded file name: reporter\reports\exporter_external_basic.py
from io import StringIO
from collections import Counter
import datetime, jinja2, xmltodict
from reporter.reports.basic_template import ReportTemplate


class ExporterExternalBasic(ReportTemplate):
    def __init__(self, sources, mapper_dict, template_path, display_host):
        super().__init__(sources)
        self.template_path = template_path
        self.display_host = display_host
        self.mapper_dict = mapper_dict

    @staticmethod
    def get_mapper_dict(mapper_path):
        with open(mapper_path, "rb") as (f):
            result = xmltodict.parse(f)
            result = result["Compliance"]["Categories"]["Category"]
        for category in result:
            associations = dict()
            associations["AlertTag"] = set()
            associations["AlertAppId"] = set()
            if "Associations" in category:
                if category["Associations"]:
                    assoc_dict = category["Associations"]["Association"]
                    if isinstance(assoc_dict, list):
                        for assoc in assoc_dict:
                            if "@AlertTag" in assoc:
                                associations["AlertTag"].add(assoc["@AlertTag"])
                            if "@AlertAppId" in assoc:
                                associations["AlertAppId"].add(assoc["@AlertAppId"])

            category["Associations"] = associations

        return result

    def parts(self):
        template_loader = jinja2.FileSystemLoader(searchpath="data/templates/reports/")
        template_env = jinja2.Environment(loader=template_loader)
        template_vars = {}
        template = template_env.get_template(self.template_path)
        vulnerability_type_name_counter = Counter()
        data = StringIO()
        template_vars["template_part"] = "start"
        data.write(self.remove_blank_lines(template.render(template_vars)))
        data.seek(0)
        yield data
        data = StringIO()
        for source in self.sources:
            not_processed_vulns = set()
            if self.display_host:
                template_vars["template_part"] = "host_start"
                template_vars["scan_info"] = self.get_well_formed_scan_info(source)
                data.write(self.remove_blank_lines(template.render(template_vars)))
                data.seek(0)
                yield data
                data = StringIO()
            alert_cnt = 0
            for vulnerability, location, vulnerability_type in source.vulnerabilities():
                was_added = False
                for category in self.mapper_dict:
                    vuln_template_vars = dict()
                    vuln_template_vars.update(template_vars)
                    has_vuln_tag = False
                    try:
                        vuln_template_vars["f5_threat"] = [
                            "info",
                            "low",
                            "medium",
                            "critical",
                        ][vulnerability_type["severity"]]
                    except (IndexError, KeyError):
                        pass

                    vuln_status = vulnerability.get("status", "open")
                    if vuln_status == "fixed":
                        vuln_template_vars["f5_status"] = "closed"
                    else:
                        if vuln_status == "open":
                            vuln_template_vars["f5_status"] = "open"
                        else:
                            not_processed_vulns.add(vulnerability_type["name"])
                            continue
                        first_seen = vulnerability.get("first_seen")
                        if first_seen is None:
                            first_seen = source.info().get("start_date")
                        if first_seen is not None:
                            vuln_template_vars["f5_opened"] = int(
                                first_seen.timestamp()
                            )
                    if "tags" in vulnerability_type:
                        if category["Associations"]:
                            if vulnerability_type["tags"]:
                                has_vuln_tag = category["Associations"][
                                    "AlertTag"
                                ].intersection(vulnerability_type["tags"])
                    if (
                        vulnerability["app_id"]
                        in category["Associations"]["AlertAppId"]
                        or has_vuln_tag
                    ):
                        vuln_template_vars[
                            "processed_request"
                        ] = self.get_request_parts(vulnerability.get("request") or "")
                        vuln_template_vars["vulnerability_type_name"] = category[
                            "@Index"
                        ]
                        vuln_template_vars["alert_cnt"] = alert_cnt
                        vuln_template_vars["severity"] = self.get_severity_string(
                            vulnerability_type["severity"]
                        )
                        vulnerability["request"] = self.escape_html(
                            vulnerability.get("request") or ""
                        )
                        vulnerability["attack_vector"] = self.normalize_encoding(
                            vulnerability.get("attack_vector")
                        )
                        vuln_template_vars["vulnerability"] = vulnerability
                        vuln_template_vars["category"] = category
                        vuln_template_vars["vulnerability_type"] = vulnerability_type
                        vulnerability_type_name_counter.update(
                            (vulnerability_type["name"],)
                        )
                        c = vulnerability_type_name_counter[vulnerability_type["name"]]
                        vuln_template_vars[
                            "vulnerability_type_name_indexed"
                        ] = "%s %s" % (vulnerability_type["name"], c)
                        vuln_template_vars["location"] = location
                        vuln_template_vars[
                            "scan_info"
                        ] = self.get_well_formed_scan_info(source)
                        vuln_template_vars["template_part"] = "vulnerability_item"
                        data.write(
                            self.remove_blank_lines(template.render(vuln_template_vars))
                        )
                        data.seek(0)
                        yield data
                        data = StringIO()
                        alert_cnt += 1
                        was_added = True

                if not was_added:
                    not_processed_vulns.add(vulnerability_type["name"])

            template_vars["template_part"] = "not_processed_vulnerability"
            template_vars["not_processed_vulns"] = not_processed_vulns
            data.write(self.remove_blank_lines(template.render(template_vars)))
            data.seek(0)
            yield data
            data = StringIO()
            if self.display_host:
                template_vars["template_part"] = "host_end"
                data.write(self.remove_blank_lines(template.render(template_vars)))
                data.seek(0)
                yield data
                data = StringIO()

        template_vars["template_part"] = "end"
        data.write(self.remove_blank_lines(template.render(template_vars)))
        data.seek(0)
        yield data
